//
//  Alert.swift
//  FrameProduct
//
//  Created by delegate on 2024/2/3.
//

import UIKit

/// 按照UE文档中设计定义的提示框
///
/// 示例代码1:
/// 通过链式调用，当前页面弹出一个内容为“请阅读用户服务协议和隐私政策并勾选”的提示框，并有取消和确认按钮，需要用户点击确认或者取消后，才会消失
///
///     Alert.with(title: "标题", message: "我是内容啊啊啊啊", style: .alert, type: .custom)
///         .bind(action: AlertAction(title: "取消", style: .cancel))
///         .bind(button: "确定", isEnabled: false)
///         .bind(textField: nil, placeholder: "请输入你的想法", isSecure: false)
///         .show()
///
public struct Alert: Alertable {
    
    public typealias Style = UIAlertController.Style
    public typealias Action = AlertAction
    
    /// 弹框类型，共两种
    public enum AlertType {
        /// 系列的UIAlertController
        case system
        /// 自定义的AlertController，样式与UIAlertController相似，只是根据需求自定义了某些样式
        case custom
    }
    
    var alertController: AlertControllerable
    let alertType: AlertType
  
    @discardableResult
    public static func with(title: String? = nil, message: String? = nil, style: Style, type: AlertType) -> Self {
        let alertType: AlertType = type
        switch alertType {
        case .system:
            let alertController = UIAlertController(title: title, message: message, preferredStyle: style)
            return Alert(alertController: alertController, alertType: alertType)
        default:
            let alertController = AlertController(title: title, message: message, preferredStyle: style)
            return Alert(alertController: alertController, alertType: alertType)
        }
    }
    
    @discardableResult
    public static func with(title: String? = nil, message: String? = nil, style: Style) -> Alert {
        with(title: title, message: message, style: style, type: .system)
    }
    
    @discardableResult
    public static func custom(title: NSAttributedString? = nil, message: NSAttributedString? = nil, style: Style) -> Self {
        let alertController = AlertController.init(title: title, message: message, view: nil, preferredStyle: style)
        return Alert(alertController: alertController, alertType: .custom)
    }
    
    @discardableResult
    public func bind(action: Action) -> Self {
        self.alertController.addAction(action)
        return self
    }
    
    /// 给弹框 添加一个按钮
    ///
    /// - Parameters:
    ///   - title: 设置的按钮的标题
    ///   - style: 设置的按钮的样式
    ///   - isEnabled: 设置的按钮的是否可响应
    ///   - handler: 设置的按钮的点击回调
    /// - Returns:
    ///   - 返回一个Alert 实例本身
    @discardableResult
    public func bind(button title: String, style: Action.Style = .default, isEnabled: Bool = true, handler: ((Action) -> Void)? = nil) -> Self {
        let action = Action(title: title, style: style, handler: handler)
        action.isEnabled = isEnabled
        return bind(action: action)
    }
}


public extension AlertPresentable where Self == Alert {
    @discardableResult
    func show(on convertible: ViewConvertible? = nil, completion: (() -> Void)? = nil) -> Self {
        
        if let vc = convertible?.asViewController {
            if UIScreen.main.traitCollection.userInterfaceIdiom == .pad {
                self.alertController.modalPresentationStyle = .popover
                if let popoverPC = self.alertController.popoverPresentationController {
                    popoverPC.sourceView = vc.view
                    popoverPC.sourceRect = CGRect(x: vc.view.bounds.midX,
                                                  y: vc.view.bounds.midY,
                                                  width: 0,
                                                  height: 0)
                    popoverPC.permittedArrowDirections = []
                }
            }
            vc.present(self.alertController, animated: true, completion: completion)
            return self
        }
        
        guard let rootVC = UIApplication.lxs.topViewController else {
            print("顶层控制器不能为空 at: \(#file), func: \(#function), line: \(#line)")
            return self
        }
        
        if UIScreen.main.traitCollection.userInterfaceIdiom == .pad {
            self.alertController.modalPresentationStyle = .popover
            if let popoverPC = self.alertController.popoverPresentationController {
                popoverPC.sourceView = rootVC.view
                popoverPC.sourceRect = CGRect(x: rootVC.view.bounds.midX,
                                              y: rootVC.view.bounds.midY,
                                              width: 0,
                                              height: 0)
                popoverPC.permittedArrowDirections = []
            }
        }
        rootVC.present(self.alertController, animated: true, completion: completion)
        
        return self
    }
    
    func dismiss(animated: Bool = true) {
        self.alertController.dismiss(animated: animated, completion: nil)
    }
}

public extension AlertTextFieldBindable where Self == Alert {
    

    func bind(textField text: String? = nil, placeholder: String, isSecure: Bool = false, configurationHandler: ((UITextField) -> Void)? = nil) -> Alert {
        self.alertController.addTextField { (customTextField) in
            
            customTextField.text = text
            customTextField.placeholder = placeholder
            customTextField.isSecureTextEntry = isSecure
            customTextField.editingChangedWithBlock {
//                /// 查找当前window显示的弹框UIAlertController
//                guard let alertWindow = UIApplication.shared.windows.filter({ $0.rootViewController?.presentedViewController is AlertControllerable }).first else {
//                    return
//                }
//                guard let alertController = alertWindow.rootViewController?.presentedViewController as? AlertControllerable else {
//                    return
//                }
                
                var textFields: [UITextField]?
                
                if let vc = self.alertController as? UIAlertController {
                    textFields = vc.textFields
                    
                    /// 获取alert 的 输入框和确认按钮，当输入框都输入文本时，确认按钮才可以被响应，否则确认按钮处于disabled状态
                    guard let usernameTextfield = textFields?.first,
                        let passwordTextfield = textFields?.last,
                        let confirmAction = vc.actions.last else { return }
                    confirmAction.isEnabled = (((usernameTextfield.text?.count ?? 0) > 0) && ((passwordTextfield.text?.count ?? 0) > 0))
                }
                else if let vc = self.alertController as? AlertController {
                    textFields = vc.textFields
                    /// 获取alert 的 输入框和确认按钮，当输入框都输入文本时，确认按钮才可以被响应，否则确认按钮处于disabled状态
                    guard let usernameTextfield = textFields?.first,
                        let passwordTextfield = textFields?.last,
                        let confirmAction = vc.actions.last else { return }
                    confirmAction.isEnabled = (((usernameTextfield.text?.count ?? 0) > 0) && ((passwordTextfield.text?.count ?? 0) > 0))
                }
                
            }
            
            if let closure = configurationHandler {
                closure(customTextField)
            }
        }
        return self
    }
}

extension Alert: AlertTextFieldBindable { }

/// 规范AlertController的协议
public protocol AlertControllerable: UIViewController {
    func addAction(_ wrappedAction: AlertAction)
    func addTextField(configurationHandler: ((UITextField) -> Void)?)
}

extension AlertControllerable where Self: UIAlertController {
    public func addAction(_ wrappedAction: AlertAction) {
        let action = UIAlertAction(title: wrappedAction.title, style: wrappedAction.style) { _ in
            if let block = wrappedAction.handler {
                block(wrappedAction)
            }
        }
        action.isEnabled = wrappedAction.isEnabled
        self.addAction(action)
    }
}

extension UIAlertController: AlertControllerable {}
extension AlertController: AlertControllerable {}

private struct UITextFieldkeys {
    static var actionBlock = "actionBlock"
}

extension UITextField {
    
   fileprivate func editingChangedWithBlock(_ block: (() -> Void)?) {
        self.actionBlock = block
        self.addTarget(self, action: #selector(editingChangedAction), for: .editingChanged)
    }
    
    private var actionBlock: (() -> Void)? {
        set {
            objc_setAssociatedObject(self, &UITextFieldkeys.actionBlock, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC)
        }
        get {
            return objc_getAssociatedObject(self, &UITextFieldkeys.actionBlock)  as? () -> Void
        }
    }
    @objc private func editingChangedAction() {
        if let block = actionBlock {
            block()
        }
    }
}
